---
title: 'React Native'
date: '2022-08-11'
images: ['https://p7.itc.cn/images01/20230419/15fe12c4bed84169809e64a45f6a1716.png']
summary: 'React Native 是一个使用 JavaScript 和 React 来构建移动应用的框架，它允许开发者使用一套代码同时开发 iOS 和 Android 应用。'
tags: 
 - APP
---


## React Native 前期准备

[React Native 官方文档](https://reactnative.dev/docs/getting-started)
[React Native 中文网](https://reactnative.cn/docs/getting-started)

### 环境搭建

- 1. 安装 [Node.js](https://nodejs.org/zh-cn)
- 2. 安装 [JDK](https://www.oracle.com/java/technologies/downloads/)
- 3. 安装 [androiddevtools](https://www.androiddevtools.cn/#sdk-tools)
- 4. 安装 [Android Studio](https://developer.android.google.cn/studio) 和 Android SDK
- 5. 安装 Xcode 和 CocoaPods -- IOS环境
  - Xcode 是 Apple 开发的集成开发环境，用于开发 iOS 应用。
  - CocoaPods 是一个用于管理 iOS 项目依赖的第三方库，React Native 项目需要使用 CocoaPods 来管理依赖。
- 6. 配置环境变量
- 7. Hyper-V 相关设置

> 在window系统下只能开发 android，mac 系统可以同时开发 ios 和 android

### expo cli

[expo](https://expo.dev/) 是一个用于开发 React Native 应用的工具，它提供了一套命令行工具和一套开发环境，可以让开发者更方便地开发 React Native 应用。

```bash
# 全局安装脚手架
npm install -g expo-cli

# 创建项目
expo init MyApp
cd MyApp
# 启动项目 yarn start
expo start

# 直接创建项目
npx create-expo-app@latest
```
> 项目运行在 http://localhost:8081/   exp://192.168.142.252:8081

```bash
› Using Expo Go
› Press s │ switch to development build

› Press a │ open Android
› Press w │ open web   # 打开浏览器

› Press j │ open debugger
› Press r │ reload app
› Press m │ toggle menu
› shift+m │ more tools
› Press o │ open project code in your editor  # 打开编辑器

› Press ? │ show all commands
```

![项目结构](https://kodo.huixiangwuyou.com/blog/images/app/20250616223019.png)


### react-native cli

[react-native cli](https://reactnative.dev/docs/environment-setup) 是 React Native 官方提供的命令行工具，它提供了一套命令行工具和一套开发环境，可以让开发者更方便地开发 React Native 应用。
```bash
# 全局安装脚手架
npm install -g react-native-cli

# 创建项目
npx react-native init MyApp
cd MyApp
# 启动项目
npx react-native run-ios
npx react-native run-android
# 启动模拟器后时间可能有点长，需要等待
# 创建项目目录 src/compnonents src/routes src/screens src/utils

# 添加项目依赖
yarn add react-native-elements react-native-vector-icons react-native-safe-area-context
```

> 新版本替代  使用 @react-native-community/cli 代替了旧的 react-native-cli

```bash
npm install -g @react-native-community/cli
npx react-native init MyApp
```

> SafeAreaView

react-native-safe-area-context是处理安全区域的库。提供SafeAreaView，虽然这个组件在rn中也有，但是rn中的只⽀持
ios10+，不⽀持ios和android的⽼版本。项⽬中建议选择react-native-safe-area-contex的SafeAreaView。

### 其他常用工具

- [scrcpy](https://github.com/Genymobile/scrcpy) 安卓投屏工具

### 示例代码
```js
import React, {useState} from 'react';
import { View, Text, StyleSheet, SafeAreaView, Image,
 ImageBackground, TextInput, ScrollView,} from 'react-native';
import {Button} from 'react-native-elements';
const logo = 'https://zh-hans.reactjs.org/logo-og.png';

export default function App() {
 const [count, setCount] = useState(0);
 const [text, setText] = useState('default');
 return (
  <SafeAreaView>
    <ScrollView>
      <Text>App</Text>
      <Image source={{uri: logo}} style={styles.logo}/>
      <ImageBackground source={{uri: logo}} style={styles.logo}>
      <Text style={{color: 'white'}}>Inside</Text>
      </ImageBackground>
      <Button title={count + ''}
      onPress={() => setCount(count + 1)}
      buttonStyle={styles.btn}/>
      <TextInput value={text}
      onChangeText={txt => setText(txt)}
      style={styles.txt}/>
      <Text style={[styles.txt, {borderColor:'green'}]}>
        <Text style={styles.bold}>⽂本: </Text>
        <Text>{text}</Text>
      </Text>
      <View style={[styles.txt, {borderColor:'green'}]}>
        <Text style={styles.bold}>⽂本: </Text>
        <Text>{text}</Text>
      </View>
      {/* //! 溢出 */}
      <Text>omg:</Text>
      <Text numberOfLines={1}>{'书名'.repeat(100)}</Text>
      {/* <Text>{'书名'.repeat(1000)}</Text> */}
    </ScrollView>
  </SafeAreaView>
 );
}

const styles = StyleSheet.create({
 logo: {
  width: 100,
  height: 100,
 },
 btn: {
  width: 100,
  height: 100,
  backgroundColor: 'red',
 },
 txt: {
  width: 100,
  height: 100,
  backgroundColor: 'yellow',
 },
 bold: {
   fontWeight: 'bold',
 },
});
```

### 与其他框架的对比

![React Native 与其他框架的对比](https://kodo.huixiangwuyou.com/blog/images/app/20250616174757.png)

![APP 开发对比](https://kodo.huixiangwuyou.com/blog/images/app/20250616174933.png)


## React Native UI

![视图和移动](https://reactnative.dev/docs/assets/diagram_ios-android-views.svg)
| React Native UI 组件 | Android 视图 | iOS 视图 | 	web | 描述 |
| --- | --- | --- | --- | --- |
| &lt;View&gt; | &lt;ViewGroup&gt; | &lt;UIView&gt; | &lt;div&gt; | 支持使用弹性框、样式、一些触摸处理和可访问性控件进行布局的容器 |
| &lt;Text&gt; | &lt;TextView&gt; | &lt;UITextView&gt; | &lt;p&gt; | 显示、设置样式、嵌套文本字符串，甚至处理触摸事件 |
| &lt;Image&gt; | &lt;ImageView&gt; | &lt;UIImageView&gt; | &lt;img&gt; | 显示不同类型的图像 |
| &lt;ScrollView&gt; | &lt;ScrollView&gt; | &lt;UIScrollView&gt; | &lt;div&gt; | 可包含多个组件和视图的通用滚动容器 |
| &lt;TextInput&gt; | &lt;EditText&gt; | &lt;UITextField&gt; | &lt;input type="text"&gt; | 允许用户输入文本 |
|  |  |  |  |  |

### 样式
在react native中，样式是通过StyleSheet.create()方法来创建的，这个方法接受一个对象，对象的属性名是样式名，属性值是样式值。
样式属性示例
```js
import Dimensions from 'react-native-dimensions';

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    alignItems: 'center',
    justifyContent: 'center',
    width: Dimensions.get('window').width/4, // 获取屏幕宽度设置几分之一
    height:100
  },
  text: {
    fontSize: 20,
    color: '#000',
  },
});
```
> 样式没有继承性，Text 的样式可以继承,尺寸大小没有单位

### 常用组件
[参考](https://reactnative.dev/docs/components-and-apis)

- TouchableOpacity: 创建一个可点击的组件
- TouchableHighlight: 创建一个可点击的组件，并且在点击时会有一个高亮效果
- TouchableWithoutFeedback: 创建一个可点击的组件，并且在点击时不会有任何效果
- Modal: 创建一个模态框
- SectionList: 创建一个列表，可以分组显示
- Keyboard
- Animated
- PanResponder
- DrawerLayoutAndroid
- DrawerLayout
- ViewPagerAndroid
- ViewPager
- WebView
- Picker
- Alert: 显示一个警告对话框
- StatusBar: 状态栏组件
- Button: 创建一个按钮
- ActivityIndicator: 加载指示器
- DatePickerAndroid: 显示一个日期选择器
- DrawerLayoutAndroid: 创建一个抽屉布局
- FlatList: 高性能列表组件
- Image: 显示一个图片
- KeyboardAvoidingView: 避免键盘遮挡
- Modal: 创建一个模态框
- Picker: 创建一个选择器


## 导航跳转

React Native并没有浏览器那样的历史栈，所以React Navigation就来做这件事了。
``` 
yarn add @react-navigation/native react-native-screens react-native-safe-area-context
```

React Navigation 提供了三种类型的导航器：
- Stack Navigator：栈导航器，用于管理页面之间的跳转，类似于浏览器的历史栈。
  - yarn add @react-navigation/native-stack
- Tab Navigator：标签导航器，用于在多个页面之间进行切换，类似于浏览器的标签页。
- Drawer Navigator：抽屉导航器，用于在多个页面之间进行切换，类似于浏览器的侧边栏。

### Stack Navigator

createNativeStackNavigator是⼀个函数，返回⼀个对象，这个对象⾥有两个都是React组件的属性：Screen and Navigator。注意它们的包裹关系：NavigationContainer->Navigator->Screen
Screen属性：
- name：路由名称，⽤于标识路由，必须唯⼀
- component：该路由对应的组件
- options：该路由的配置项，例如标题、头部样式等,也可以通过options的title修改
- initialParams：给组件参数

Navigator属性：
- initialRouteName：初始路由名称，默认为第一个路由
- screenOptions：全局路由配置项，例如标题、头部样式等


```js
// app.js
import React from 'react';
import {NavigationContainer} from '@reactnavigation/native';
import RootRouter from './RootRouter';

export deault function App () {
 return (
 <NavigationContainer>
 <RootRouter />
 </NavigationContainer>
 );
}

// RootRouter.js
import React from 'react';
import {View, Text} from 'react-native';
import {createNativeStackNavigator} from '@react-navigation/native-stack';
import HomeScreen from '@/screens/HomeScreen';
import UserScreen from '@/screens/UserScreen';

const {Screen, Navigator} =createNativeStackNavigator();
export default function RootRouter() {
 return (
 // ! SafeAreaView不能写这⾥
 // <SafeAreaView>
 <Navigator>
 <Screen name="home" component={HomeScreen} />
 <Screen name="user"
 component={UserScreen}
 options={{title: '⽤户中⼼'}}
 initialParams={{name: '我是⼩明'}}
 />
 </Navigator>
 // </SafeAreaView>
 );
}

// Link跳转
<Link to={{screen: 'user', params: {id: 'jane'}}}>
 Go to Jane's profile
</Link>
```
### navigation
```js
// navigation.navigate('home', {screen: 'home', params: {id: 'jane'}});
// 事件跳转
<Button
 title="go home"
 onPress={() => {
 // navigation.push('home');
 // navigation.navigate('home');
 }}
 />
```
⻚⾯是否已经存在，执⾏navigation.navigate导致的结果是不同的。如果⻚⾯已经存在，执⾏navigation.navigate则会回到原先的⻚⾯，并且移除原先⻚⾯在历史栈中的记录。如果⻚⾯不存在，则push⼀个新的记录到历史栈中。
但是如果你执⾏navigation.navigate的时候，给⻚⾯添加了参数，那对与历史栈来说，这个记录对于历史栈就是个新的记录了。


## 平台特定代码
[参考](https://reactnative.cn/docs/platform-specific-code)

```js
import {Platform, StyleSheet} from 'react-native';

const styles = StyleSheet.create({
  height: Platform.OS === 'ios' ? 200 : 100,
});

import {Platform, StyleSheet} from 'react-native';

const styles = StyleSheet.create({
  container: {
    flex: 1,
    ...Platform.select({
      ios: {
        backgroundColor: 'red',
      },
      android: {
        backgroundColor: 'blue',
      },
    }),
  },
});

const Component = Platform.select({
  ios: () => require('ComponentIOS'),
  android: () => require('ComponentAndroid'),
})();

<Component />;

import {Platform} from 'react-native';

if (Platform.Version === 25) {
  console.log('Running on Nougat!');
}

# 不同平台组件
BigButton.ios.js
BigButton.android.js

import BigButton from './BigButton';

```


## 注意事项

- Hooks API 是 React Native 0.59 提供的新特性
- 因为 JSX 语法糖的实质是调⽤React.createElement⽅法，所以你必须在⽂件头部引⽤import React from 'react'。




